#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>

#include "cv.h"
#include "highgui.h"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include "opencv/cv.hpp"
#include "windows.h"

using namespace cv;
using namespace std;
//using namespace cv::cuda;

#include <stdlib.h>

#include "sum_mean.hpp"
#include "omp.h"

#define TEST_TIMES 20

double getCpuClock(void)
{
	LARGE_INTEGER freq;
	LARGE_INTEGER count;
	QueryPerformanceFrequency(&freq);

	QueryPerformanceCounter(&count);

	//cout << "freq:" << freq.QuadPart << ",count:" << count.QuadPart << endl;

	return ((double)count.QuadPart) / ((double)freq.QuadPart);
}

int getMean(uchar* buffIn, unsigned int countIn, float * meanOut)
{
	double sum = .0;
	for (int i = 0; i < countIn; i++)
	{
		sum += buffIn[i];
	}
	//printf("in function getMean, sum is %f\n", sum);
	*meanOut = sum / countIn;

	return 0;
}

int getMean_omp(uchar* buffIn, unsigned int countIn, float * meanOut)
{
	double sum = .0f;
	omp_set_num_threads(4);
	int tempSum[4];
	int iTempSum = 0;
#pragma omp parallel
	{
		int temp = 0;
		int idT = omp_get_thread_num();
#pragma omp for // reduction(+: sum)		
		for (int i = 0; i < countIn; i++)
		{
			temp += buffIn[i];
		}
		tempSum[idT] = temp;

	}
	for (int i = 0; i < 4; i++)
	{
		iTempSum += tempSum[i];
	}
	sum = double(iTempSum);
	//printf("in function getMean_omp, sum is %f,tempSum0 is %d, tempSum1 is %d\n", sum, tempSum[0], tempSum[1]);
	*meanOut = sum / countIn;

	return 0;
}

int main(int argc, char *argv[])
{
	if (argc < 2)
	{
		printf("No parameter for image file name!\n");
		return -1;
	}
	Mat image;
	image = imread(argv[1], IMREAD_GRAYSCALE);

	if (!image.data)
	{
		printf("No image data \n");
		return -1;
	}

	uchar * devBuff;
//	int devBuffBlockNum;
	cudaMalloc(&devBuff, 1024 * 1024 * 20);
	cudaMemcpy(devBuff, image.data, image.cols*image.rows, cudaMemcpyHostToDevice);
	printf("width is %d, height is %d\n", image.cols, image.rows);

	double dStart = 0;
	double dEnd = 0;
	double sumTime = 0;
	double avgTime = 0;


	float meanHostVal = 0;
	sumTime = 0;
	for (int tI = 0; tI < TEST_TIMES; tI++)
	{
		dStart = getCpuClock();
		cuda_mean_1d(devBuff, (float*)(devBuff + 1024 * 1024), image.rows*image.cols, &meanHostVal);
		dEnd = getCpuClock();
		sumTime = sumTime + dEnd - dStart;
	}
	printf("cuda mean of img is %f, time cost %fs\n", meanHostVal, sumTime / TEST_TIMES);

	float meanVal = .0;

	sumTime = 0;
	for (int tI = 0; tI < TEST_TIMES; tI++)
	{
		dStart = getCpuClock();
		getMean_omp(image.data, image.rows*image.cols, &meanVal);
		dEnd = getCpuClock();
		sumTime = sumTime + dEnd - dStart;
	}
	printf("cpu omp mean of img is %f, time cost %fs\n", meanVal, sumTime / TEST_TIMES);

	meanVal = .0;
	sumTime = 0;
	for (int tI = 0; tI < TEST_TIMES; tI++)
	{
		dStart = getCpuClock();
		getMean(image.data, image.rows*image.cols, &meanVal);
		dEnd = getCpuClock();
		sumTime = sumTime + dEnd - dStart;
	}
	printf("cpu mean of img is %f, time cost %fs\n", meanVal, sumTime / TEST_TIMES);

	cudaFree(devBuff);

}